package com.sh.weblogspringboot.web.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sh.weblogspringboot.admin.event.ReadArticleEvent;
import com.sh.weblogspringboot.common.domain.dos.ArticleCategoryRelDO;
import com.sh.weblogspringboot.common.domain.dos.ArticleContentDO;
import com.sh.weblogspringboot.common.domain.dos.ArticleDO;
import com.sh.weblogspringboot.common.domain.dos.ArticleTagRelDO;
import com.sh.weblogspringboot.common.domain.dos.CategoryDO;
import com.sh.weblogspringboot.common.domain.dos.TagDO;
import com.sh.weblogspringboot.common.domain.mapper.ArticleCategoryRelMapper;
import com.sh.weblogspringboot.common.domain.mapper.ArticleContentMapper;
import com.sh.weblogspringboot.common.domain.mapper.ArticleMapper;
import com.sh.weblogspringboot.common.domain.mapper.ArticleTagRelMapper;
import com.sh.weblogspringboot.common.domain.mapper.CategoryMapper;
import com.sh.weblogspringboot.common.domain.mapper.TagMapper;
import com.sh.weblogspringboot.common.enums.ResponseCodeEnum;
import com.sh.weblogspringboot.common.exception.BizException;
import com.sh.weblogspringboot.common.util.PageResponse;
import com.sh.weblogspringboot.common.util.Response;
import com.sh.weblogspringboot.web.convert.ArticleConvert;
import com.sh.weblogspringboot.web.markdown.MarkdownHelper;
import com.sh.weblogspringboot.web.model.vo.FindCategoryListRspVO;
import com.sh.weblogspringboot.web.model.vo.FindIndexArticlePageListReqVO;
import com.sh.weblogspringboot.web.model.vo.FindIndexArticlePageListRspVO;
import com.sh.weblogspringboot.web.model.vo.FindTagListRspVO;
import com.sh.weblogspringboot.web.model.vo.article.FindArticleDetailReqVO;
import com.sh.weblogspringboot.web.model.vo.article.FindArticleDetailRspVO;
import com.sh.weblogspringboot.web.model.vo.article.FindPreNextArticleRspVO;
import com.sh.weblogspringboot.web.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author songHai
 * @Classname ArticleServiceImpl
 * @Description
 * @Date 2025/4/11 23:22
 */
@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private ArticleCategoryRelMapper articleCategoryRelMapper;

    @Autowired
    private ArticleTagRelMapper articleTagRelMapper;
    @Qualifier("articleContentMapper")
    @Autowired
    private ArticleContentMapper articleContentMapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher;


    @Override
    public Response findArticlePageList(FindIndexArticlePageListReqVO findIndexArticlePageListReqVO) {
        Long current = findIndexArticlePageListReqVO.getCurrent();
        Long size = findIndexArticlePageListReqVO.getSize();

        // 1. 分页查询文章主体记录
        Page<ArticleDO> articleDOPage = articleMapper.selectPageList(current, size, null, null, null);
        // 获取分页列表记录
        List<ArticleDO> articleDOList = articleDOPage.getRecords();

        if (CollectionUtils.isEmpty(articleDOList)) {
            return Response.success("查询成功");
        }

        // 文章DO 转VO
        List<FindIndexArticlePageListRspVO> articleVos = articleDOList.stream().map(ArticleConvert.INSTANCE::convertDO2VO).collect(Collectors.toList());

        // 获取所有文章对应ID集合
        List<Long> articleIds = articleDOList.stream().map(ArticleDO::getId).collect(Collectors.toList());

        // 2. 设置文章所属分类
        List<CategoryDO> allCategoryList = categoryMapper.selectList(Wrappers.emptyWrapper());
        // 转Map, 方便后续根据分类ID拿到对应的分类名称
        Map<Long, String> categoryIdNameMap = allCategoryList.stream().collect(Collectors.toMap(CategoryDO::getId, CategoryDO::getName));
        // 根据文章ID批量查询所有分类关联记录
        List<ArticleCategoryRelDO> articleCategoryRelDOS = articleCategoryRelMapper.selectByArticleIdS(articleIds);

        articleVos.forEach(vo -> {
            Long currentArticleId = vo.getId();
            //过滤当前文章对应分类的关联数据
            Optional<ArticleCategoryRelDO> categoryRelDOOptional = articleCategoryRelDOS.stream().filter(rel -> Objects.equals(rel.getArticleId(), currentArticleId)).findAny();
            if (categoryRelDOOptional.isPresent()) {
                FindCategoryListRspVO findCategoryListRspVO = FindCategoryListRspVO.builder()
                        .id(categoryRelDOOptional.get().getCategoryId())
                        .name(categoryIdNameMap.get(categoryRelDOOptional.get().getCategoryId()))
                        .build();
                // 添加的当前文章分类关联列表中
                vo.setCategory(findCategoryListRspVO);
            }
        });

        // 3. 设置文章标签
        // 查询所有文章标签
        List<TagDO> tagDOList = tagMapper.selectList(Wrappers.emptyWrapper());
        // 转Map, 方便后续根据标签ID拿到对应的标签名称
        Map<Long, String> mapIdNameMap = tagDOList.stream().collect(Collectors.toMap(TagDO::getId, TagDO::getName));
        // 获取所有文章的标签关联记录
        List<ArticleTagRelDO> articleTagRelDOS = articleTagRelMapper.selectByArticleIds(articleIds);
        articleVos.forEach(vo -> {
            Long currentArticleId = vo.getId();
            // 过滤单签文章对应的标签关联记录
            List<ArticleTagRelDO> articleTagRelDOSList = articleTagRelDOS.stream().filter(res -> Objects.equals(res.getArticleId(), currentArticleId)).collect(Collectors.toList());

            List<FindTagListRspVO> findTagListRspVOSList = Lists.newArrayList();
            // 将关联的标签记录DO转VO
            articleTagRelDOSList.forEach(articleTagRelDO -> {
                FindTagListRspVO temFindTagListRspVO = FindTagListRspVO.builder()
                        .id(articleTagRelDO.getId())
                        .name(mapIdNameMap.get(articleTagRelDO.getId()))
                        .build();
                findTagListRspVOSList.add(temFindTagListRspVO);
            });

            // 设置转换后的标签数据
            vo.setTags(findTagListRspVOSList);
        });

        return PageResponse.success(articleDOPage, articleVos);
    }

    @Override
    public Response findArticleDetail(FindArticleDetailReqVO findArticleDetailReqVO) {
        Long articleId = findArticleDetailReqVO.getArticleId();

        ArticleDO articleDO = articleMapper.selectById(articleId);
        if (Objects.isNull(articleDO)) {
            log.warn("==> 该文章不存在, articleId: {}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }

        // 查询正文
        ArticleContentDO articleContentDO = articleContentMapper.selectByArticleId(articleId);
        // DO转VO
        FindArticleDetailRspVO vo = FindArticleDetailRspVO.builder()
                .title(articleDO.getTitle())
                .createTime(articleDO.getCreateTime())
                .content(MarkdownHelper.convertMarkdown2Html(articleContentDO.getContent()))
                .readNum(articleDO.getReadNum())
                .build();

        // 查询所属分类
        ArticleCategoryRelDO articleCategoryRelDO = articleCategoryRelMapper.selectByArticleId(articleId);
        CategoryDO categoryDO = categoryMapper.selectById(articleCategoryRelDO.getCategoryId());
        vo.setCategoryId(categoryDO.getId());
        vo.setCategoryName(categoryDO.getName());

        // 查询标签
        List<ArticleTagRelDO> articleTagRelDOS = articleTagRelMapper.selectByArticleId(articleId);
        List<Long> tagIds = articleTagRelDOS.stream().map(ArticleTagRelDO::getTagId).collect(Collectors.toList());
        List<TagDO> tagDOList = tagMapper.selectByIds(tagIds);
        // 标签 DO 转 VO
        List<FindTagListRspVO> tagsVos = tagDOList.stream()
                .map(tagDO -> FindTagListRspVO.builder()
                        .id(tagDO.getId())
                        .name(tagDO.getName())
                        .build())
                .collect(Collectors.toList());
        vo.setTags(tagsVos);

        // 上一篇文章
        ArticleDO preArticle = articleMapper.selectPreByArticleId(articleId);
        if (Objects.nonNull(preArticle)) {
            FindPreNextArticleRspVO preArticleVo = FindPreNextArticleRspVO.builder()
                    .articleId(preArticle.getId())
                    .articleTitle(preArticle.getTitle())
                    .build();
            vo.setPreArticle(preArticleVo);
        }

        // 下一篇
        ArticleDO nextArticleDo = articleMapper.selectNextArticle(articleId);
        if (Objects.nonNull(nextArticleDo)) {
            FindPreNextArticleRspVO nextArticleVo = FindPreNextArticleRspVO.builder()
                    .articleId(nextArticleDo.getId())
                    .articleTitle(nextArticleDo.getTitle())
                    .build();
            vo.setNextArticle(nextArticleVo);
        }

        // 当获取文章详情后，添加文章被阅读事件
        eventPublisher.publishEvent(new ReadArticleEvent(this, articleId));
        return Response.success("查询成功", vo);
    }
}
